<?xml version='1.0' encoding='utf-8'?>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Pro Git - 简体中文版
</title>
    <meta content="http://www.w3.org/1999/xhtml; charset=utf-8" http-equiv="Content-Type"/>
    <link href="stylesheet.css" type="text/css" rel="stylesheet"/>
    <style type="text/css">
		@page { margin-bottom: 5.000000pt; margin-top: 5.000000pt; }</style>
  </head>
  <body class="calibre">
<h2 id="calibre_toc_29" class="calibre3">远程分支</h2>

<p class="calibre2">远程分支（remote branch）是对远程仓库状态的索引。它们是一些无法移动的本地分支；只有在进行 Git 的网络活动时才会更新。远程分支就像是书签，提醒着你上次连接远程仓库时上面各分支的位置。 </p>

<p class="calibre2">我们用 <code class="calibre9">(远程仓库名)/(分支名)</code> 这样的形式表示远程分支。比如我们想看看上次同 <code class="calibre9">origin</code> 仓库通讯时 <code class="calibre9">master</code> 的样子，就应该查看 <code class="calibre9">origin/master</code> 分支。如果你和同伴一起修复某个问题，但他们先推送了一个 <code class="calibre9">iss53</code> 分支到远程仓库，虽然你可能也有一个本地的 <code class="calibre9">iss53</code> 分支，但指向服务器上最新更新的却应该是 <code class="calibre9">origin/iss53</code> 分支。</p>

<p class="calibre2">可能有点乱，我们不妨举例说明。假设你们团队有个地址为 <code class="calibre9">git.ourcompany.com</code> 的 Git 服务器。如果你从这里克隆，Git 会自动为你将此远程仓库命名为 <code class="calibre9">origin</code>，并下载其中所有的数据，建立一个指向它的 <code class="calibre9">master</code> 分支的指针，在本地命名为 <code class="calibre9">origin/master</code>，但你无法在本地更改其数据。接着，Git 建立一个属于你自己的本地 <code class="calibre9">master</code> 分支，始于 <code class="calibre9">origin</code> 上 <code class="calibre9">master</code> 分支相同的位置，你可以就此开始工作（见图 3-22）：</p>

<p class="calibre2"><img src="18333fig0322-tn.png" alt="图 3-22. 一次 Git 克隆会建立你自己的本地分支 master 和远程分支 origin/master，它们都指向 origin/master 分支的最后一次提交。" title="图 3-22. 一次 Git 克隆会建立你自己的本地分支 master 和远程分支 origin/master，它们都指向 origin/master 分支的最后一次提交。" class="calibre5"/></p>

<p class="calibre2">要是你在本地 <code class="calibre9">master</code> 分支做了会儿事情，与此同时，其他人向 <code class="calibre9">git.ourcompany.com</code> 推送了内容，更新了上面的 <code class="calibre9">master</code> 分支，那么你的提交历史会开始朝不同的方向发展。不过只要你不和服务器通讯，你的 <code class="calibre9">origin/master</code> 指针不会移动（见图 3-23）。</p>

<p class="calibre2"><img src="18333fig0323-tn.png" alt="图 3-23. 在本地工作的同时有人向远程仓库推送内容会让提交历史发生分歧。" title="图 3-23. 在本地工作的同时有人向远程仓库推送内容会让提交历史发生分歧。" class="calibre5"/></p>

<p class="calibre2">可以运行 <code class="calibre9">git fetch origin</code> 来进行同步。该命令首先找到 <code class="calibre9">origin</code> 是哪个服务器（本例为 <code class="calibre9">git.ourcompany.com</code>），从上面获取你尚未拥有的数据，更新你本地的数据库，然后把 <code class="calibre9">origin/master</code> 的指针移到它最新的位置（见图 3-24）。</p>

<p class="calibre2"><img src="18333fig0324-tn.png" alt="图 3-24. git fetch 命令会更新 remote 索引。" title="图 3-24. git fetch 命令会更新 remote 索引。" class="calibre5"/></p>

<p class="calibre2">为了演示拥有多个远程分支（不同的远程服务器）的项目是个什么样，我们假设你还有另一个仅供你的敏捷开发小组使用的内部服务器 <code class="calibre9">git.team1.ourcompany.com</code>。可以用第二章中提到的 <code class="calibre9">git remote add</code> 命令把它加为当前项目的远程分支之一。我们把它命名为 <code class="calibre9">teamone</code>，表示那一整串 Git 地址（见图 3-25）。</p>

<p class="calibre2"><img src="18333fig0325-tn.png" alt="图 3-25. 把另一个服务器加为远程仓库" title="图 3-25. 把另一个服务器加为远程仓库" class="calibre5"/></p>

<p class="calibre2">现在你可以用 <code class="calibre9">git fetch teamone</code> 来获取小组服务器上你还没有的数据了。由于当前该服务器上的内容是你 <code class="calibre9">origin</code> 服务器上的子集，Git 不会下载任何数据，而只是简单地创建一个名为 <code class="calibre9">teamone/master</code> 的分支来指向 <code class="calibre9">teamone</code> 服务器上 <code class="calibre9">master</code> 所指向的更新 <code class="calibre9">31b8e</code>（见图 3-26）。</p>

<p class="calibre2"><img src="18333fig0326-tn.png" alt="图 3-26. 你在本地有了一个指向 teamone 服务器上 master 分支的索引。" title="图 3-26. 你在本地有了一个指向 teamone 服务器上 master 分支的索引。" class="calibre5"/></p>

<h3 id="calibre_toc_123" class="calibre4">推送</h3>

<p class="calibre2">要想和其他人分享某个分支，你需要把它推送到一个你拥有写权限的远程仓库。你的本地分支不会被自动同步到你引入的远程分支中，除非你明确执行推送操作。换句话说，对于无意分享的，你尽可以保留为私人分支，而只推送那些协同工作的特性分支。</p>

<p class="calibre2">如果你有个叫 <code class="calibre9">serverfix</code> 的分支需要和他人一起开发，可以运行 <code class="calibre9">git push (远程仓库名) (分支名)</code>：</p>

<pre class="calibre8"><code class="calibre9">$ git push origin serverfix
Counting objects: 20, done.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (15/15), 1.74 KiB, done.
Total 15 (delta 5), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
 * [new branch]      serverfix -&gt; serverfix
</code></pre>

<p class="calibre2">这其实有点像条捷径。Git 自动把 <code class="calibre9">serverfix</code> 分支名扩展为 <code class="calibre9">refs/heads/serverfix:refs/heads/serverfix</code>，意为“取出我的 serverfix 本地分支，推送它来更新远程仓库的 serverfix 分支”。我们将在第九章进一步介绍 <code class="calibre9">refs/heads/</code> 部分的细节，不过一般使用的时候都可以省略它。也可以运行 <code class="calibre9">git push origin serverfix:serferfix</code> 来实现相同的效果，它的意思是“提取我的 serverfix 并更新到远程仓库的 serverfix”。通过此语法，你可以把本地分支推送到某个命名不同的远程分支：若想把远程分支叫作 <code class="calibre9">awesomebranch</code>，可以用 <code class="calibre9">git push origin serverfix:awesomebranch</code> 来推送数据。</p>

<p class="calibre2">接下来，当你的协作者再次从服务器上获取数据时，他们将得到一个新的远程分支 <code class="calibre9">origin/serverfix</code>：</p>

<pre class="calibre8"><code class="calibre9">$ git fetch origin
remote: Counting objects: 20, done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 15 (delta 5), reused 0 (delta 0)
Unpacking objects: 100% (15/15), done.
From git@github.com:schacon/simplegit
 * [new branch]      serverfix    -&gt; origin/serverfix
</code></pre>

<p class="calibre2">值得注意的是，在 fetch 操作抓来新的远程分支之后，你仍然无法在本地编辑该远程仓库。换句话说，在本例中，你不会有一个新的 <code class="calibre9">serverfix</code> 分支，有的只是一个你无法移动的 <code class="calibre9">origin/serverfix</code> 指针。</p>

<p class="calibre2">如果要把该内容合并到当前分支，可以运行 <code class="calibre9">git merge origin/serverfix</code>。如果想要一份自己的 <code class="calibre9">serverfix</code> 来开发，可以在远程分支的基础上分化出一个新的分支来：</p>

<pre class="calibre8"><code class="calibre9">$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch refs/remotes/origin/serverfix.
Switched to a new branch "serverfix"
</code></pre>

<p class="calibre2">这会切换到新建的 <code class="calibre9">serverfix</code> 本地分支，其内容同远程分支 <code class="calibre9">origin/serverfix</code> 一致，你可以在里面继续开发了。</p>

<h3 id="calibre_toc_124" class="calibre4">跟踪分支</h3>

<p class="calibre2">从远程分支检出的本地分支，称为<em class="calibre11">跟踪分支(tracking branch)</em>。跟踪分支是一种和远程分支有直接联系的本地分支。在跟踪分支里输入 <code class="calibre9">git push</code>，Git 会自行推断应该向哪个服务器的哪个分支推送数据。反过来，在这些分支里运行 <code class="calibre9">git pull</code> 会获取所有远程索引，并把它们的数据都合并到本地分支中来。</p>

<p class="calibre2">在克隆仓库时，Git 通常会自动创建一个 <code class="calibre9">master</code> 分支来跟踪 <code class="calibre9">origin/master</code>。这正是 <code class="calibre9">git push</code> 和 <code class="calibre9">git pull</code> 一开始就能正常工作的原因。当然，你可以随心所欲地设定为其它跟踪分支，比如 <code class="calibre9">origin</code> 上除了 <code class="calibre9">master</code> 之外的其它分支。刚才我们已经看到了这样的一个例子：<code class="calibre9">git checkout -b [分支名] [远程名]/[分支名]</code>。如果你有 1.6.2 以上版本的 Git，还可以用 <code class="calibre9">--track</code> 选项简化：</p>

<pre class="calibre8"><code class="calibre9">$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch refs/remotes/origin/serverfix.
Switched to a new branch "serverfix"
</code></pre>

<p class="calibre2">要为本地分支设定不同于远程分支的名字，只需在前个版本的命令里换个名字：</p>

<pre class="calibre8"><code class="calibre9">$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch refs/remotes/origin/serverfix.
Switched to a new branch "sf"
</code></pre>

<p class="calibre2">现在你的本地分支 <code class="calibre9">sf</code> 会自动向 <code class="calibre9">origin/serverfix</code> 推送和抓取数据了。</p>

<h3 id="calibre_toc_125" class="calibre4">删除远程分支</h3>

<p class="calibre2">如果不再需要某个远程分支了，比如搞定了某个特性并把它合并进了远程的 <code class="calibre9">master</code> 分支（或任何其他存放稳定代码的地方），可以用这个非常无厘头的语法来删除它：<code class="calibre9">git push [远程名] :[分支名]</code>。如果想在服务器上删除 <code class="calibre9">serverfix</code> 分支，运行下面的命令：</p>

<pre class="calibre8"><code class="calibre9">$ git push origin :serverfix
To git@github.com:schacon/simplegit.git
 - [deleted]         serverfix
</code></pre>

<p class="calibre2">咚！服务器上的分支没了。你最好特别留心这一页，因为你一定会用到那个命令，而且你很可能会忘掉它的语法。有种方便记忆这条命令的方法：记住我们不久前见过的 <code class="calibre9">git push [远程名] [本地分支]:[远程分支]</code> 语法，如果省略 <code class="calibre9">[本地分支]</code>，那就等于是在说“在这里提取空白然后把它变成<code class="calibre9">[远程分支]</code>”。</p>

</body>
</html>
